﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using BaseUtil;
using UnityEngine;

public class XMLBuffHelper
{
    public static void WriteToBuf<T>(Dictionary<int, T> map_data, NetOutStream outs) where T : IXMLData
    {
        var count = map_data.Count;
        outs.Write(count);
        var iter = map_data.Keys.GetEnumerator();
        while (iter.MoveNext())
        {
            var key = iter.Current;
            outs.Write(key);
            var data = map_data[key];
            data.WriteToBuf(outs);
        }
    }

    public static void WriteToBuf(Dictionary<int, List<int>> map_data, NetOutStream outs)
    {
        var count = map_data.Count;
        outs.Write(count);
        var iter = map_data.Keys.GetEnumerator();
        while (iter.MoveNext())
        {
            var key = iter.Current;
            outs.Write(key);
            var data = map_data[key];
            WriteToBuf(data, outs);
        }
    }

    public static void WriteToBuf<T>(Dictionary<string, T> map_data, NetOutStream outs) where T : IXMLData
    {
        var count = map_data.Count;
        outs.Write(count);
        var iter = map_data.Keys.GetEnumerator();
        while (iter.MoveNext())
        {
            var key = iter.Current;
            outs.Write(key);
            var data = map_data[key];
            data.WriteToBuf(outs);
        }
    }

    public static void WriteToBuf<T1, T2>(Dictionary<T1, T2> map_data, NetOutStream outs)
        where T1 : IXMLData, IComparer<T1>, new()
        where T2 : IXMLData, new()
    {
        var count = map_data.Count;
        outs.Write(count);
        var iter = map_data.Keys.GetEnumerator();
        while (iter.MoveNext())
        {
            var key = iter.Current;
            key.WriteToBuf(outs);
            var data = map_data[key];
            data.WriteToBuf(outs);
        }
    }

    public static void ReadFromBuf<T1, T2>(ref Dictionary<T1, T2> map_data, NetInStream ins)
        where T1 : IXMLData, IComparer<T1>, new()
        where T2 : IXMLData, new()
    {
        var count = 0;
        ins.Read(ref count);
        map_data = new Dictionary<T1, T2>(count);
        for (var i = 0; i < count; ++i)
        {
            var key = new T1();
            key.ReadFromBuf(ins);
            var data = new T2();
            data.ReadFromBuf(ins);
            map_data[key] = data;
        }
    }

    public static void ReadFromBuf<T>(ref Dictionary<int, T> map_data, NetInStream ins) where T : IXMLData, new()
    {
        var count = 0;
        ins.Read(ref count);
        map_data = new Dictionary<int, T>(count);
        for (var i = 0; i < count; ++i)
        {
            var key = 0;
            ins.Read(ref key);
            var data = new T();
            data.ReadFromBuf(ins);
            map_data[key] = data;
        }
    }

    public static void ReadFromBuf<T>(ref Dictionary<string, T> map_data, NetInStream ins) where T : IXMLData, new()
    {
        var count = 0;
        ins.Read(ref count);
        map_data = new Dictionary<string, T>(count);
        for (var i = 0; i < count; ++i)
        {
            var key = "";
            ins.Read(ref key);
            var data = new T();
            data.ReadFromBuf(ins);
            map_data[key] = data;
        }
    }

    public static void WriteToBuf(Dictionary<int, string> map_data, NetOutStream outs)
    {
        var count = map_data.Count;
        outs.Write(count);
        var iter = map_data.Keys.GetEnumerator();
        while (iter.MoveNext())
        {
            var key = iter.Current;
            outs.Write(key);
            outs.Write(map_data[key]);
        }
    }

    public static void WriteToBuf(Dictionary<string, string> map_data, NetOutStream outs)
    {
        var count = map_data.Count;
        outs.Write(count);
        var iter = map_data.Keys.GetEnumerator();
        while (iter.MoveNext())
        {
            var key = iter.Current;
            outs.Write(key);
            outs.Write(map_data[key]);
        }
    }


    public static void WriteToBuf(Dictionary<int, int> map_data, NetOutStream outs)
    {
        var count = map_data.Count;
        outs.Write(count);
        var iter = map_data.Keys.GetEnumerator();
        while (iter.MoveNext())
        {
            var key = iter.Current;
            outs.Write(key);
            outs.Write(map_data[key]);
        }
    }

    public static void ReadFromBuf(ref Dictionary<int, string> map_data, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        map_data = new Dictionary<int, string>(count);
        for (var i = 0; i < count; ++i)
        {
            var key = 0;
            ins.Read(ref key);

            var value = "";
            ins.Read(ref value);
            map_data[key] = value;
        }
    }

    public static void ReadFromBuf(ref Dictionary<int, int> map_data, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        map_data = new Dictionary<int, int>(count);
        for (var i = 0; i < count; ++i)
        {
            var key = 0;
            ins.Read(ref key);

            var value = 0;
            ins.Read(ref value);
            map_data[key] = value;
        }
    }

    public static void ReadFromBuf(ref Dictionary<string, string> map_data, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        map_data = new Dictionary<string, string>(count);
        for (var i = 0; i < count; ++i)
        {
            var key = string.Empty;
            ins.Read(ref key);

            var value = string.Empty;
            ins.Read(ref value);
            map_data[key] = value;
        }
    }

    public static void ReadFromBuf(ref Dictionary<int, List<int>> map_data, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        map_data = new Dictionary<int, List<int>>(count);
        for (var i = 0; i < count; ++i)
        {
            var key = 0;
            ins.Read(ref key);
            var value = new List<int>();
            ReadFromBuf(ref value, ins);
            map_data[key] = value;
        }
    }

    public static void WriteToBuf<T>(List<List<T>> list_list_data, NetOutStream outs) where T : IXMLData
    {
        var count = list_list_data.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            var list_data = list_list_data[i];
            var list_count = list_data.Count;
            outs.Write(list_count);
            for (var j = 0; j < list_count; j++)
            {
                var data = list_data[j];
                data.WriteToBuf(outs);
            }
        }
    }

    public static void WriteToBuf(List<List<int>> list_list_data, NetOutStream outs)
    {
        var count = list_list_data.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            var list_data = list_list_data[i];
            var list_count = list_data.Count;
            outs.Write(list_count);
            for (var j = 0; j < list_count; j++)
            {
                var data = list_data[j];
                outs.Write(data);
            }
        }
    }

    public static void ReadFromBuf(ref List<List<int>> list_list_data, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        list_list_data.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var list_data = new List<int>();
            var list_count = 0;
            ins.Read(ref list_count);
            list_data.Capacity = list_count;
            for (var j = 0; j < list_count; ++j)
            {
                var data = 0;
                ins.Read(ref data);
                list_data.Add(data);
            }

            list_list_data.Add(list_data);
        }
    }

    public static void ReadFromBuf<T>(ref List<List<T>> list_list_data, NetInStream ins) where T : IXMLData, new()
    {
        var count = 0;
        ins.Read(ref count);
        list_list_data.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var list_data = new List<T>();
            var list_count = 0;
            ins.Read(ref list_count);
            list_data.Capacity = list_count;
            for (var j = 0; j < list_count; ++j)
            {
                var data = new T();
                data.ReadFromBuf(ins);
                list_data.Add(data);
            }

            list_list_data.Add(list_data);
        }
    }

    public static void WriteToBuf<T>(List<T> listdata, NetOutStream outs) where T : IXMLData
    {
        var count = listdata.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            var data = listdata[i];
            data.WriteToBuf(outs);
        }
    }

    public static void ReadFromBuf<T>(ref List<T> listData, NetInStream ins) where T : IXMLData, new()
    {
        var count = 0;
        ins.Read(ref count);
        listData.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var data = new T();
            data.ReadFromBuf(ins);
            listData.Add(data);
        }
    }

    public static void WriteToBuf(List<int> listdata, NetOutStream outs)
    {
        var count = listdata.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            outs.Write(listdata[i]);
        }
    }

    public static void WriteToBuf<T>(ArrayList listdata, NetOutStream outs) where T : IXMLData
    {
        var count = listdata.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            var data = (T) listdata[i];
            data.WriteToBuf(outs);
        }
    }

    public static void ReadFromBuf<T>(ref ArrayList listdata, NetInStream ins) where T : IXMLData, new()
    {
        var count = 0;
        ins.Read(ref count);
        listdata.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var data = new T();
            data.ReadFromBuf(ins);
            listdata.Add(data);
        }
    }

    public static void ReadFromBuf(ref Vector3 vec3, NetInStream ins)
    {
        float x = 0;
        float y = 0;
        float z = 0;
        ins.Read(ref x);
        ins.Read(ref y);
        ins.Read(ref z);
        vec3.x = x;
        vec3.y = y;
        vec3.z = z;
    }

    public static void WriteToBuf(Vector3 vec3, NetOutStream outs)
    {
        outs.Write(vec3.x);
        outs.Write(vec3.y);
        outs.Write(vec3.z);
    }

    public static void WriteToBuf(Vector2 vec, NetOutStream outs)
    {
        outs.Write(vec.x);
        outs.Write(vec.y);
    }

    public static void ReadFromBuf(ref Vector2 vec, NetInStream ins)
    {
        ins.Read(ref vec.x);
        ins.Read(ref vec.y);
    }

    public static void ReadFromBuf(ref List<int> listdata, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        listdata.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var n = 0;
            ins.Read(ref n);
            listdata.Add(n);
        }
    }

    public static void WriteToBuf(List<string> listdata, NetOutStream outs)
    {
        var count = listdata.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            outs.Write(listdata[i]);
        }
    }

    public static void ReadFromBuf(ref List<string> listdata, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        listdata.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var str = "";
            ins.Read(ref str);
            listdata.Add(str);
        }
    }

    public static void WriteToBuf(List<bool> listdata, NetOutStream outs)
    {
        var count = listdata.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            outs.Write(listdata[i]);
        }
    }

    public static void ReadFromBuf(ref List<bool> listdata, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        listdata.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var b = true;
            ins.Read(ref b);
            listdata.Add(b);
        }
    }

    public static void WriteToBuf(List<long> listdata, NetOutStream outs)
    {
        var count = listdata.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            outs.Write(listdata[i]);
        }
    }

    public static void ReadFromBuf(ref List<long> listdata, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        listdata.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var tmpl = 0L;
            ins.Read(ref tmpl);
            listdata.Add(tmpl);
        }
    }

    public static void WriteToBuf(List<float> listdata, NetOutStream outs)
    {
        var count = listdata.Count;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            outs.Write(listdata[i]);
        }
    }

    public static void ReadFromBuf(ref List<float> listdata, NetInStream ins)
    {
        var count = 0;
        ins.Read(ref count);
        listdata.Capacity = count;
        for (var i = 0; i < count; ++i)
        {
            var f = 0f;
            ins.Read(ref f);
            listdata.Add(f);
        }
    }

    public static void WriteToBuf<T>(T[] arraydata, NetOutStream outs) where T : IXMLData
    {
        var count = arraydata.Length;
        outs.Write(count);
        for (var i = 0; i < count; ++i)
        {
            arraydata[i].WriteToBuf(outs);
        }
    }

    public static void ReadFromBuf<T>(ref T[] arraydata, NetInStream ins) where T : IXMLData, new()
    {
        var count = 0;
        ins.Read(ref count);
        arraydata = new T[count];
        for (var i = 0; i < count; ++i)
        {
            arraydata[i] = new T();
            arraydata[i].ReadFromBuf(ins);
        }
    }

    public static void WriteEnumToBuf<T>(T _enum, NetOutStream outs)
    {
        var value = Convert.ToInt32(_enum);
        outs.Write(value);
    }

    public static void ReadEnumFromBuf<T>(ref T _enum, NetInStream ins)
    {
        var value = 0;
        ins.Read(ref value);
        _enum = (T) Enum.ToObject(typeof(T), value);
    }

    public static void SaveBuffToFile(byte[] buff, int length, string file_path)
    {
        if (File.Exists(file_path))
        {
            FileUtil.DeleteFile(file_path, EnumFileType.PERSISTENT);
        }

        var fs = new FileStream(file_path, FileMode.OpenOrCreate);
        var mStreamWriter = new StreamWriter(fs);
        mStreamWriter.AutoFlush = true;
        mStreamWriter.BaseStream.Write(buff, 0, length);
        mStreamWriter.Close();
    }

    public static string GetLocalLogFolder()
    {
        return GetLocalStorageFolder();
    }

    public static string GetLocalStorageFolder()
    {
#if (UNITY_EDITOR)
        return Application.dataPath + "/../dressbuf/";
#elif(UNITY_ANDROID || UNITY_IOS)
        return Application.persistentDataPath + "/";
#elif CONSOLE_CLIENT
        return  "/";
#else
        return Application.dataPath + "/../dressbuf/";

#endif
    }

    public static string GetUTF8String(byte[] buffer)
    {
        if (buffer == null)
            return null;

        if (buffer.Length <= 3)
        {
            return Encoding.UTF8.GetString(buffer);
        }

        byte[] bomBuffer = {0xef, 0xbb, 0xbf};

        if (buffer[0] == bomBuffer[0]
            && buffer[1] == bomBuffer[1]
            && buffer[2] == bomBuffer[2])
        {
            return new UTF8Encoding(false).GetString(buffer, 3, buffer.Length - 3);
        }

        return Encoding.UTF8.GetString(buffer);
    }

    public static T ReadXmlBuf<T>(string fileName) where T : IXMLData
    {
        var xmlObj = XMLBufFileReader.ReadXmlBuf(fileName);
        if (null == xmlObj)
        {
#if USE_LOGWRAPPER
            LogWrapper.LogError("Load config error, FileName: ", fileName);
#endif
            return null;
        }

        var data = xmlObj as T;
        if (null == data)
        {
#if USE_LOGWRAPPER
            LogWrapper.LogError("Config type cast error, FileName: ", fileName);
#endif
            return null;
        }

        return data;
    }
}

public class XmlParseHelper
{
    public static bool ParseAttrSByte(XmlNode itemNode, string attrName, ref sbyte ret_int)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
#if USE_LOGWRAPPER
            LogWrapper.LogError("Parser item error , not found", attrName);
#endif
            return false;
        }

        ret_int = XmlConvert.ToSByte(temp_attr.Value);

        return true;
    }

    public static bool ParseAttrInt(XmlNode itemNode, string attrName, ref int ret_int)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
#if USE_LOGWRAPPER
            LogWrapper.LogError("Parser item error , {0} not found", attrName);
#endif
            return false;
        }

        ret_int = XmlConvert.ToInt32(temp_attr.Value);

        return true;
    }

    public static bool ParseAttrFloat(XmlNode itemNode, string attrName, ref float ret_float)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
#if USE_LOGWRAPPER
            LogWrapper.LogError("Parser item error , {0} not found", attrName);
#endif
            return false;
        }

        ret_float = XmlConvert.ToSingle(temp_attr.Value);

        return true;
    }

    public static bool ParseAttrDouble(XmlNode itemNode, string attrName, ref double ret_float)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
#if USE_LOGWRAPPER
            LogWrapper.LogError("Parser item error , {0} not found", attrName);
#endif
            return false;
        }

        ret_float = XmlConvert.ToDouble(temp_attr.Value);

        return true;
    }

    public static bool ParseAttrBool(XmlNode itemNode, string attrName, ref bool ret_bool)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
#if USE_LOGWRAPPER
            LogWrapper.LogError("Parser item error , {0} not found", attrName);
#endif
            return false;
        }

        ret_bool = XmlConvert.ToBoolean(temp_attr.Value.ToLower());

        return true;
    }

    public static bool ParseAttrString(XmlNode itemNode, string attrName, ref string ret_string)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
#if USE_LOGWRAPPER
            LogWrapper.LogError("Parser item error , {0} not found", attrName);
#endif
            return false;
        }

        ret_string = temp_attr.Value;

        return true;
    }

    public static void ParseAttrStringDefault(XmlNode itemNode, string attrName, ref string ret_string,
        string s_default)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
            ret_string = s_default;
        }
        else
        {
            ret_string = temp_attr.Value;
        }
    }

    public static void ParseAttrFloatDefault(XmlNode itemNode, string attrName, ref float ret_float, float f_default)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
            ret_float = f_default;
        }
        else
        {
            ret_float = XmlConvert.ToSingle(temp_attr.Value);
        }
    }

    public static void ParseAttrBoolDefault(XmlNode itemNode, string attrName, ref bool ret_bool, bool b_default)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
            ret_bool = b_default;
        }
        else
        {
            ret_bool = XmlConvert.ToBoolean(temp_attr.Value.ToLower());
        }
    }

    /// <summary>
    /// </summary>
    /// <param name="itemNode"></param>
    /// <param name="attrName"></param>
    /// <param name="ret_int"></param>
    /// <param name="n_default"></param>
    /// <returns> true:ret_int == attr, false: ret_int = n_default</returns>
    public static bool ParseAttrIntDefault(XmlNode itemNode, string attrName, ref int ret_int, int n_default)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
            ret_int = n_default;
            return false;
        }

        ret_int = XmlConvert.ToInt32(temp_attr.Value);
        return true;
    }

    public static bool ParseAttrSbyteDefault(XmlNode itemNode, string attrName, ref sbyte ret_byte, sbyte n_default)
    {
        var temp_attr = itemNode.Attributes[attrName];
        if (temp_attr == null)
        {
            ret_byte = n_default;
            return false;
        }

        ret_byte = XmlConvert.ToSByte(temp_attr.Value);
        return true;
    }

    public static void ParseNodeStringDefault(XmlNode itemNode, string node_path, ref string ret_string,
        string s_default)
    {
        var singleNode = itemNode.SelectSingleNode(node_path);
        if (null != singleNode)
        {
            ret_string = singleNode.InnerText;
        }
        else
        {
            ret_string = s_default;
        }
    }

    public static void ParseNodeIntDefault(XmlNode itemNode, string node_path, ref int ret_int, int n_default)
    {
        var singleNode = itemNode.SelectSingleNode(node_path);
        if (null != singleNode)
        {
            ret_int = XmlConvert.ToInt32(singleNode.InnerText);
        }
        else
        {
            ret_int = n_default;
        }
    }

    public static bool ParseNodeInt(XmlNode itemNode, string node_path, ref int ret_int)
    {
        var singleNode = itemNode.SelectSingleNode(node_path);
        if (null == singleNode)
        {
            return false;
        }

        ret_int = XmlConvert.ToInt32(singleNode.InnerText);
        return true;
    }

    public static bool ParseNodeFloat(XmlNode itemNode, string node_path, ref float ret_float)
    {
        var singleNode = itemNode.SelectSingleNode(node_path);
        if (null == singleNode)
        {
            return false;
        }

        ret_float = XmlConvert.ToSingle(singleNode.InnerText);
        return true;
    }

    public static bool ParseNodeStringList(XmlNode itemNode, string node_path, List<string> ret_list)
    {
        var node_list = itemNode.SelectNodes(node_path);
        if (null == node_list)
        {
            return false;
        }

        for (var i = 0; i < node_list.Count; ++i)
        {
            ret_list.Add(node_list[i].InnerText);
        }

        return true;
    }

    public static bool ParseNodeIntList(XmlNode itemNode, string node_path, List<int> ret_list)
    {
        var node_list = itemNode.SelectNodes(node_path);
        if (null == node_list)
        {
            return false;
        }

        for (var i = 0; i < node_list.Count; ++i)
        {
            ret_list.Add(XmlConvert.ToInt32(node_list[i].InnerText));
        }

        return true;
    }

    public static void ParseNodeShortDefault(XmlNode itemNode, string node_path, ref short ret_short, short n_default)
    {
        if (itemNode.Attributes != null && itemNode.Attributes[node_path] != null)
        {
            ret_short = XmlConvert.ToInt16(itemNode.Attributes[node_path].Value);
        }
        else
        {
            ret_short = n_default;
        }
    }
}